package com.xuecheng.media.service.jobhandler;

import com.xuecheng.base.utils.Mp4VideoUtil;
import com.xuecheng.media.model.po.MediaProcess;
import com.xuecheng.media.service.MediaFileProcessService;
import com.xuecheng.media.service.MediaFileService;
import com.xxl.job.core.context.XxlJobHelper;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * 视频处理任务
 */
@Slf4j
@Component
public class VideoTask {

    @Autowired
    private MediaFileProcessService mediaFileProcessService;
    @Autowired
    private MediaFileService mediaFileService;
    @Value("${videoprocess.ffmpegpath}")
    private String ffmpegpath;
    /**
     * 视频处理任务
     */
    @XxlJob("videoJobHandler")
    public void videoJobHandler() throws Exception {

        // 分片参数
        int shardIndex = XxlJobHelper.getShardIndex();  //执行器的编号，从0开始
        int shardTotal = XxlJobHelper.getShardTotal();  //执行器的总数
        //cpu核数
        int processor = Runtime.getRuntime().availableProcessors();

        //查询任务
        List<MediaProcess> mediaProcessList = mediaFileProcessService.getMediaProcessList(shardIndex, shardTotal, processor);

        //任务数
        int size = mediaProcessList.size();
        log.debug("取到的视频任务数:{}",size);
        if( size < 0 ) {
            return;
        }
        //线程池处理
        ExecutorService executorService = Executors.newFixedThreadPool(size);
        //使用计数器
        CountDownLatch countDownLatch = new CountDownLatch(size);
        mediaProcessList.forEach(mediaProcess->{
            //将任务加入到线程池处理
            executorService.execute(()->{
                try {
                    //任务id
                    Long taskId = mediaProcess.getId();
                    //文件名--md5
                    String fileId = mediaProcess.getFileId();
                    //获取锁
                    boolean b = mediaFileProcessService.startTask(taskId);
                    if (!b) {
                        log.debug("抢占任务失败,taskId:{}",taskId);
                        return ;
                    }
                    String bucket = mediaProcess.getBucket();
                    String objectName = mediaProcess.getFilePath();
                    //从minio下载视频
                    File file = mediaFileService.downloadFileFromMinIO(bucket, objectName);
                    if(file == null) {
                        log.debug("下载文件失败，任务id:{},bucket:{}，objectName:{}",taskId,bucket,objectName);
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"下载文件到本地失败");
                        return ;
                    }
                    //源avi的路径
                    String video_path = file.getAbsolutePath();

                    //转换后的文件路径
                    File mp4File = null ;
                    try {
                        mp4File = File.createTempFile("mp4",".mp4");
                    } catch (IOException e) {
                        log.debug("创建临时文件失败，{}",e.getMessage());
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"创建临时文件失败");
                        return ;
                    }
                    //执行转码任务
                    String mp4FilePath = mp4File.getAbsolutePath();
                    String result = "";
                    try {
                        Mp4VideoUtil mp4VideoUtil = new Mp4VideoUtil(ffmpegpath, video_path, mp4File.getName(), mp4FilePath);
                        result = mp4VideoUtil.generateMp4();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    if(!result.equals("success")) {
                        log.debug("视频转码失败，原因:{}，bucket:{},objectName:{}",result,bucket,objectName);
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,result);
                        return;
                    }
                    //上传到minio
                    objectName = getFilePathByMd5(fileId,".mp4");
                    boolean b1 = mediaFileService.addMediaFilesToMinIO(mp4FilePath, "video/mp4", bucket, objectName);
                    if(!b1) {
                        log.debug("上传文件到MInio失败，taskid:{}",taskId);
                        mediaFileProcessService.saveProcessFinishStatus(taskId,"3",fileId,null,"上传文件到MInio失败");
                        return;
                    }
                    //文件的url
                    String url = "/" + bucket + "/" + objectName;
                    //保存任务处理结果
                    mediaFileProcessService.saveProcessFinishStatus(mediaProcess.getId(), "2",fileId,url,null);
                    objectName = getFilePathByMd5(fileId,".avi");
                    mediaFileService.removeFileFromMinIO(bucket,objectName);
                } finally {
                    //计数器减1
                    countDownLatch.countDown();
                }

            });
        });
        //指定最大限度的等待时间
        countDownLatch.await(30, TimeUnit.MINUTES);
    }
    /**
     * 得到合并后的文件的地址
     * @param fileMd5 文件id即md5值
     * @param fileExt 文件扩展名
     * @return
     */
    private String getFilePathByMd5(String fileMd5,String fileExt){
        return   fileMd5.substring(0,1) + "/" + fileMd5.substring(1,2) + "/" + fileMd5 + "/" +fileMd5 +fileExt;
    }
}
